home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / GCC 1.37.1r14 / usr / gcc-1.37.1r14 / non-obj files / StandardGetFolder.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-24  |  20.2 KB  |  410 lines  |  [TEXT/KAHL]

  1. /*******************************************************************************
  2. * StandardGetFolder.c                                                          *
  3. *                                                                              *
  4. *    This little chunk o' code implements a way to let the user choose a       *
  5. *    folder to save files in via a StandardFile Dialog.                        *
  6. *                                                                              *
  7. *    Since the code uses the CustomGetFile function and depends on the use of  *
  8. *    FSSpec records, it only works under System 7.0 or later.                  *                        
  9. *                                                                              *
  10. *    And don't forget to include the custom dialog resources ( a 'DITL' and    *
  11. *   'DLOG') in your project.                                                   *                                                                   *
  12. *                                                                              *
  13. *    Portions of this code were originally provided by Paul Forrester          *
  14. *    (paulf@apple.com) to the think-c internet mailing list in response to my  *
  15. *    my question on how to do exactly what this code does.  I've added a       *
  16. *    couple of features, such as the ability to handle aliased folders and     *
  17. *    the programmer definable prompt.  I also cleaned and tightened the code,  *
  18. *    stomped a couple of bugs, and packaged it up neatly.  Bunches of work,    *
  19. *    but I learned A LOT about Standard File, the File Manager, the Dialog     *
  20. *    Manager, and the Alias Manager.  I tried to include in the comments some  *
  21. *    of the neat stuff I discovered in my hours of pouring over Inside Mac.    *
  22. *    Hope you find it educational as well as useful.                           *
  23. *******************************************************************************/
  24.  
  25. #if 0
  26. #include <stdio.h>
  27. #include <String.h>
  28. #endif
  29. #include <Script.h>
  30. #include <Aliases.h>
  31.  
  32. /*=============================================================================+
  33. |                            Function Prototypes                               |
  34. +=============================================================================*/
  35. long GetSFCurDir(void);
  36.  
  37. short GetSFVRefNum(void);
  38.  
  39. pascal Boolean MyCustomGetDirectoryFileFilter(  CInfoPBPtr  myPB, 
  40.                                                 Ptr         myDataPtr);
  41.  
  42. void SetButtonTitle ( Handle    ButtonHdl, 
  43.                       Str255    name, 
  44.                       Rect      *ButtonRect);
  45.  
  46. pascal short MyCustomGetDirectoryDlogHook( short        item, 
  47.                                            DialogPtr    theDialog,
  48.                                            Ptr          myDataPtr);
  49.  
  50. char *StrCpy (char *s1, char *s2);
  51.  
  52. char *StrCat (char *s1, char *s2);                                      
  53.  
  54.  
  55. /*=============================================================================+
  56. |                               Resource IDs                                   |
  57. +=============================================================================*/
  58. #define rGetFolderButton            10
  59. #define rGetFolderMessage           11
  60. #define kFolderBit                  0x0010  
  61. #define rGetFolderDialog            2008
  62.  
  63.  
  64. /*=============================================================================+
  65. |                             Global Variables                                 |
  66. +=============================================================================*/
  67. static  char    gCurrentSelectedFolder [256];
  68.  
  69.  
  70. /*******************************************************************************
  71. * StandardGetFolder                                                            *
  72. *                                                                              *
  73. *     The StandardGetFolder function. You pass it the point where you want the *
  74. *     standard file dialog box drawn, the prompt to display above the file     *
  75. *     list, and a pointer to an StandardFileReply record.                      *
  76. *                                                                              *
  77. *     Upon return, the sfFile field of the SFReply record contains the volume  *
  78. *     reference number and directory ID that specify the folder the user       *
  79. *     chose. It also passes back the name of the chosen folder.  The sfGood    *
  80. *     field is set to true if the user chose a folder, or false if not.        *
  81. *******************************************************************************/
  82.  
  83. void StandardGetFolder (    Point               where,
  84.                             Str255              message,
  85.                             StandardFileReply   *mySFReply)
  86.                             
  87. {
  88.     SFTypeList              theTypeList;
  89.     short                   numTypes;
  90.     ProcPtr                 myModalFilter;
  91.     CInfoPBRec              pb;
  92.     OSErr                   err;
  93.     short                   theItem;
  94.  
  95.     /*-------------------------------------------------------------------------+
  96.     | Setting num types to -1 tells CustomGetFile to pass all files and        |
  97.     | folders to the file filter function.                                     |
  98.     +-------------------------------------------------------------------------*/
  99.     numTypes = - 1;         
  100.  
  101.     /*-------------------------------------------------------------------------+
  102.     | Copy the prompt to be displayed above the file list into the name field  |
  103.     | of the SFReply record. When MyCustomGetDirectoryDlogHook is called for   |
  104.     | the first time, it will use this info to draw the prompt.                |
  105.     +-------------------------------------------------------------------------*/
  106.     StrCpy ( (char *) mySFReply->sfFile.name, (char *) message);
  107.     
  108.     /*-------------------------------------------------------------------------+
  109.     | Call CustomGetFile. Pass it a pointer to the file filter and dialog      |  
  110.     | hook functions. Also pass a pointer to mySFReply in the user data field. |
  111.     +-------------------------------------------------------------------------*/
  112.     CustomGetFile(  (ProcPtr)MyCustomGetDirectoryFileFilter, 
  113.                     numTypes,
  114.                     theTypeList,
  115.                     mySFReply, 
  116.                     rGetFolderDialog, 
  117.                     where,
  118.                     (ProcPtr)MyCustomGetDirectoryDlogHook, 
  119.                     NULL, 
  120.                     (short*)NULL,
  121.                     NULL, 
  122.                     (void *)(mySFReply));
  123.  
  124.     /*-------------------------------------------------------------------------+
  125.     | Ok, now the reply record contains the volume reference number and the    |
  126.     | name of the selected folder. We need to use PBGetCatInfo to get the      |    
  127.     | directory ID of the selected folder.                                     |
  128.     +-------------------------------------------------------------------------*/
  129.     pb.hFileInfo.ioCompletion = NULL;
  130.     pb.hFileInfo.ioNamePtr = mySFReply->sfFile.name;
  131.     pb.hFileInfo.ioVRefNum = mySFReply->sfFile.vRefNum;
  132.     pb.hFileInfo.ioFDirIndex = 0;
  133.     pb.hFileInfo.ioDirID = mySFReply->sfFile.parID;
  134.  
  135.     err = PBGetCatInfoSync( &pb);
  136.     
  137.     /*-------------------------------------------------------------------------+
  138.     | Insert your error handler here. I couldn't think of one so I left it     |
  139.     | empty. Works fine without it.                                            |
  140.     +-------------------------------------------------------------------------*/
  141.     if (  err != noErr);
  142.     
  143.     /*-------------------------------------------------------------------------+
  144.     | Copy the directory ID of the selected folder to the sfFile field of the  |
  145.     | SFReply record.                                                          |
  146.     +-------------------------------------------------------------------------*/
  147.     mySFReply->sfFile.parID = pb.dirInfo.ioDrDirID;
  148.  
  149. }
  150.  
  151.  
  152.  
  153. /*******************************************************************************
  154. * MyCustomGetDirectoryFileFilter                                               *
  155. *                                                                              *
  156. *     This is the file filter passed to CustomGetFile. It passes folders only. *
  157. *******************************************************************************/
  158. pascal Boolean
  159. MyCustomGetDirectoryFileFilter( CInfoPBPtr  myPB, 
  160.                                 Ptr         myDataPtr )
  161. {
  162.     return( ! (myPB->hFileInfo.ioFlAttrib & kFolderBit ) );
  163. }
  164.  
  165.  
  166. /*******************************************************************************
  167. * MyCustomGetDirectoryDlogHook                                                 *
  168. *                                                                              *
  169. *     This function lets us process item hits in the GetFolderDialog.  We're   *
  170. *     only interested if the user hit the selectFolder button. We pass all     *
  171. *     other item hits back to ModalDialog.                                     *
  172. *******************************************************************************/
  173.  
  174. pascal short MyCustomGetDirectoryDlogHook(  short       item, 
  175.                                             DialogPtr   theDialog, 
  176.                                             Ptr         myDataPtr )
  177. {
  178.  
  179.     WindowPeek      dlgPeek;
  180.     Str255          selectedName;
  181.     CInfoPBRec      pb;
  182.     short           MyCustomGetDirectoryDlogHook;
  183.     OSErr           err;
  184.     short           itemType;           
  185.     Rect            itemRect;                                   
  186.     Handle          itemHandle;
  187.     Boolean         isAlias,
  188.                     isFolder;
  189.  
  190.     StandardFileReply           *mySFRPtr;
  191.  
  192.     
  193.     
  194.     /*-------------------------------------------------------------------------+
  195.     | Set the return value to defualt to the item that was passed in.          |
  196.     +-------------------------------------------------------------------------*/
  197.     MyCustomGetDirectoryDlogHook = item;
  198.  
  199.     /*-------------------------------------------------------------------------+
  200.     | CustomGet calls dialog hook for both main and subsidiary dialog boxes.   |
  201.     | Make sure that dialog record indicates that this is the main GetFolder   |
  202.     | dialog.                                                                  |
  203.     +-------------------------------------------------------------------------*/
  204.     dlgPeek = (WindowPeek)(theDialog);
  205.     if ( (OSType)(dlgPeek->refCon) == sfMainDialogRefCon )
  206.     {
  207.         /*---------------------------------------------------------------------+
  208.         | Get a handle to the select folder button, in case we need to change  |
  209.         | the label.                                                           |
  210.         +---------------------------------------------------------------------*/
  211.         GetDItem(theDialog, rGetFolderButton, &itemType, &itemHandle, &itemRect);
  212.  
  213.         /*---------------------------------------------------------------------+
  214.         | If this is the first time the dialog hook has been called...         |
  215.         +---------------------------------------------------------------------*/
  216.         if ( item == sfHookFirstCall )
  217.         {
  218.             /*-----------------------------------------------------------------+
  219.             | Set the prompt displayed above the file list...                  |
  220.             +-----------------------------------------------------------------*/
  221.             GetDItem ( theDialog, rGetFolderMessage, &itemType, &itemHandle, 
  222.                         &itemRect );
  223.             mySFRPtr = (StandardFileReply *)(myDataPtr);
  224.             SetIText ( itemHandle, mySFRPtr->sfFile.name );
  225.  
  226.             /*-----------------------------------------------------------------+
  227.             | And the name of the currently selected folder in the select      |
  228.             | folder button.                                                   |
  229.             +-----------------------------------------------------------------*/
  230.             pb.hFileInfo.ioCompletion = NULL;
  231.             pb.hFileInfo.ioNamePtr = (StringPtr)selectedName;
  232.             pb.hFileInfo.ioVRefNum = GetSFVRefNum();
  233.             pb.hFileInfo.ioDirID = GetSFCurDir();
  234.             pb.hFileInfo.ioFDirIndex = -1;
  235.             err = PBGetCatInfoSync( &pb);
  236.  
  237.             /*-----------------------------------------------------------------+
  238.             | Note that this error return is important! When the dialog hook   |
  239.             | is called for the first time, Super Boomerang (and possibly      |
  240.             | Norton directory assistance aren't finished doing their          |
  241.             | rebounting, so the values returned by GetSFVRefNum and           |
  242.             | GetSFCurDir may not be valid, and hence PBGetCatInfo will return |
  243.             | an error.  That one took me a while to figure out.               |
  244.             +-----------------------------------------------------------------*/
  245.             if ( err != noErr )
  246.             {
  247.                 return (MyCustomGetDirectoryDlogHook);
  248.             }
  249.             
  250.             GetDItem(theDialog, rGetFolderButton, &itemType, &itemHandle, 
  251.                      &itemRect);
  252.             SetButtonTitle( itemHandle, selectedName, &itemRect);
  253.         }
  254.         
  255.         else
  256.         {
  257.             /*-----------------------------------------------------------------+
  258.             | Cast myDataPtr back to a SFReply pointer.                        |
  259.             +-----------------------------------------------------------------*/
  260.             mySFRPtr = (StandardFileReply *)( myDataPtr );
  261.  
  262.  
  263.             /*-----------------------------------------------------------------+
  264.             | If the selected folder is an alias, resolve it. isFolder will    |
  265.             | be set to true if a folder or aliased folder is selected.        |
  266.             +-----------------------------------------------------------------*/
  267.             ResolveAliasFile (&(mySFRPtr->sfFile), TRUE, &isFolder, &isAlias);
  268.             if ( (isAlias) && (isFolder) )
  269.                 StrCpy( (char *)selectedName, (char *)mySFRPtr->sfFile.name );
  270.                 
  271.             /*-----------------------------------------------------------------+
  272.             | If the selected item is a folder or volume, just copy the name   |
  273.             | into selectedName...                                             |
  274.             +-----------------------------------------------------------------*/
  275.             else if (( mySFRPtr->sfIsFolder) || (mySFRPtr->sfIsVolume) )
  276.                 StrCpy( (char *)selectedName, (char *)mySFRPtr->sfFile.name );
  277.  
  278.             /*-----------------------------------------------------------------+
  279.             | Otherwise, copy the name of the selected item's parent directory |
  280.             | into selectedName.                                               |
  281.             +-----------------------------------------------------------------*/
  282.             else
  283.             {
  284.                 pb.hFileInfo.ioCompletion = NULL;
  285.                 pb.hFileInfo.ioNamePtr = (StringPtr)selectedName;
  286.                 pb.hFileInfo.ioVRefNum = mySFRPtr->sfFile.vRefNum;
  287.                 pb.hFileInfo.ioDirID = mySFRPtr->sfFile.parID;
  288.                 pb.hFileInfo.ioFDirIndex = -1;
  289.                 err = PBGetCatInfoSync( &pb);
  290.                 if ( err != noErr)
  291.                     return (MyCustomGetDirectoryDlogHook);
  292.             }
  293.             
  294.             /*-----------------------------------------------------------------+
  295.             | If the selected folder has changed since the last call to this   |
  296.             | dialog hook function, re-draw the button with the new selected   |
  297.             | folder name.                                                     |
  298.             +-----------------------------------------------------------------*/
  299.             if ( !EqualString( selectedName, (StringPtr)gCurrentSelectedFolder, 
  300.                                 FALSE, FALSE ) ) 
  301.                 SetButtonTitle(itemHandle, selectedName, &itemRect);
  302.  
  303.             /*-----------------------------------------------------------------+
  304.             | If the user clicked the select folder button, force a cancel and |
  305.             | set the sfGood field of the Reply record to true.                |
  306.             +-----------------------------------------------------------------*/
  307.             if (item == rGetFolderButton)
  308.             {
  309.                 MyCustomGetDirectoryDlogHook = sfItemCancelButton;
  310.                 mySFRPtr->sfGood = TRUE;
  311.             }
  312.                 
  313.         }
  314.     }
  315.     
  316.     return  (MyCustomGetDirectoryDlogHook );
  317. }
  318.  
  319.  
  320.  
  321. /*******************************************************************************
  322. * SetButtonTitle                                                               *
  323. *                                                                              *
  324. *     Whenever the selected folder is changed, SetButtonTitle is called to     *
  325. *     redraw the get folder button.  Pass it a handle to the button, the new   *
  326. *     string to be drawn in the button, and a pointer to the rect the button   *
  327. *     is drawn within.                                                         *
  328. *******************************************************************************/
  329. void SetButtonTitle(    Handle      ButtonHdl, 
  330.                         Str255      name, 
  331.                         Rect        *ButtonRect )
  332. {
  333.     short   resultCode;
  334.     short   width;
  335.     char    TmpStr[ 256 ];
  336.  
  337.     StrCpy( gCurrentSelectedFolder, (char*) name );
  338.     
  339.     /*-------------------------------------------------------------------------+
  340.     | Find the width left over in the button after drawing the word 'Select'   |
  341.     | the quotation marks. Truncate the new name to this length.               |
  342.     +-------------------------------------------------------------------------*/
  343.     width = (ButtonRect->right - ButtonRect->left) -
  344.             (StringWidth((StringPtr)"\pSelect \"\"") +
  345.              CharWidth('J'));
  346.     
  347.     resultCode = TruncString(width, name, smTruncEnd );
  348.     if ( resultCode < 0 );
  349.     
  350.     /*-------------------------------------------------------------------------+
  351.     | Redraw the button.                                                       |
  352.     +-------------------------------------------------------------------------*/
  353.     StrCpy ( TmpStr, (char *)"\pSelect \"");
  354.     StrCat ( TmpStr, (char *)name);
  355.     StrCat ( TmpStr, (char *)"\p\"");
  356.     SetCTitle((ControlHandle)(ButtonHdl), (StringPtr)TmpStr );
  357.     ValidRect(ButtonRect);
  358. }
  359.  
  360.  
  361. /*******************************************************************************
  362. * GetSFCurDir, GetSFVRefNum                                                    *
  363. *                                                                              *
  364. * The following set of routines are used to access a couple of low memory      *
  365. * globals that are necessary when extending Standard File.  One example is     *
  366. * trying to get the current directory while in a file filter.  These routines  *
  367. * were used to bottleneck all the low memory usage.  If the system one day     *
  368. * supports them with a trap call, then we can easily update these routines.    *
  369. *******************************************************************************/
  370.  
  371. long GetSFCurDir()
  372. {
  373.     return( CurDirStore );
  374. }
  375.  
  376. short GetSFVRefNum()
  377. {
  378.     return( - SFSaveDisk);
  379. }
  380.  
  381.  
  382. /*******************************************************************************
  383. * StrCpy                                                                       *
  384. *                                                                              *
  385. *     Just like strcpy except that it takes pascal strings as arguments.       *                                                                               *
  386. *******************************************************************************/
  387. char *StrCpy( char *s1, char *s2 )
  388. {
  389.     BlockMove( s2, s1, 1+*s2);
  390.     return s1;
  391. }
  392.  
  393.  
  394.  
  395. /*******************************************************************************
  396. * StrCat                                                                       *
  397. *                                                                              *
  398. *     Just like strcat except that it takes pascal strings as arguments.       *                                                                               *
  399. *******************************************************************************/
  400. char *StrCat( char *s1, char *s2 )
  401. {
  402.     BlockMove( s2+1, s1+*s1+1, *s2);
  403.     *s1 += *s2;
  404.     return s1;
  405. }
  406.  
  407.  
  408.  
  409.  
  410.